package WSService

import (
	"errors"
	"multimedia/conf"
	"multimedia/utils"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	log "github.com/sirupsen/logrus"
)

type UserInfo struct {
	Uid         int64  `json:"uid"`
	DeviceState int    `json:"deviceState"`
	NickName    string `json:"nickName"`
	PhotoUrl    string `json:"photoUrl"`
}
type OutPutEnv struct {
	Data  []byte
	CmdId int
}

type Session struct {
	conn      *websocket.Conn
	hub       *Hub
	output    chan *OutPutEnv
	ticker    chan int
	Uid       int64
	conferId  int64
	open      bool
	checkTime time.Time
	sync.RWMutex
}

func (s *Session) SetConferId(roomId int64) {
	s.Lock()
	defer s.Unlock()
	s.conferId = roomId
}
func (s *Session) UpdateTime() {
	s.Lock()
	defer s.Unlock()
	s.checkTime = time.Now()
}
func (s *Session) uid() int64 {
	return s.Uid
}
func (s *Session) ConferId() int64 {
	s.RLock()
	defer s.RUnlock()
	return s.conferId
}
func (s *Session) closed() bool {
	s.RLock()
	defer s.RUnlock()
	return !s.open
}

func (s *Session) WritePump() {
	defer utils.HandlePanic()
loop:
	for msg := range s.output {
		if s.closed() {
			s.errorHandler(errors.New("tried to write to a closed session"))
			break loop
		}
		if msg.Data != nil {
			log.WithField("func:", "WritePump").Infof(" write msg the msg is: %s the id is %d the confrid is:%d", string(msg.Data), s.uid(), s.conferId)
			err := s.conn.WriteMessage(websocket.TextMessage, msg.Data)
			if err != nil {
				s.errorHandler(err)
			}
		}
		if msg.CmdId == utils.CloseMsg {
			break loop
		}
	}
	s.close()
}

func (s *Session) errorHandler(err error) {
	log.WithField("func", "websocket ErrorHandler").Debugf("the uid is:%d info:%v", s.uid(), err)
}

func (s *Session) ReadPump() {
	s.conn.SetReadLimit(3145728)
	for {
		t, message, err := s.conn.ReadMessage()
		log.WithField("func", "websocket ReadPump").Debugf("the t is:%d,ms is:%s", t, string(message))

		if err != nil {
			s.errorHandler(err)
			break
		}
		s.hub.messageHandler(s, message)
	}
}

func (s *Session) IsOnTimer() bool {
	s.RLock()
	defer s.RUnlock()
	terminal := time.Since(s.checkTime)
	return terminal > (time.Duration(4*conf.ConfigFile.PingPeriod) * time.Second)
}

func (s *Session) SendMessage(p []byte, CmdId int) {
	s.RLock()
	defer s.RUnlock()
	if s.open {
		s.output <- &OutPutEnv{Data: p, CmdId: CmdId}
	} else {
		log.WithField("func", "SendMessage error").Errorf("the user is close the uid is:%d the cmdid is:%d", s.Uid, CmdId)
	}
}

func (s *Session) close() {
	s.Lock()
	defer s.Unlock()
	if !s.open {
		return
	}
	s.open = false
	s.conn.Close()
	close(s.output)
}
func (s *Session) Close(p []byte, cmdId int) {
	s.SendMessage(p, cmdId)
}
